package com.sinosoft.platform.common.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

/**
 * 文件操作工具类
 * 
 * @date 2010-11-24
 * @since JDK 1.5
 * @author dingkui
 * @version 1.0
 */
public class FileUtil extends FileUtils {

    /**
     * 使用HttpClient上传文件到远程http服务端
     * 
     * @param uploadUrl
     *            前台上传文件到后台请求的url
     * @param filePath
     *            本地文件绝对路径（包括文件名）
     * @return statusCode 远程http服务端返回的状态
     * @throws IOException
     *             IO异常
     */
    public static int httpClientUpload(String uploadUrl, String filePath) throws IOException {
        int status = 0;
        PostMethod postMethod = null;

        try {
            postMethod = new PostMethod(uploadUrl);
            // 通过以下方法可以模拟页面参数提交
            File targetFile = new File(filePath);
            Part[] parts = { 
                    new FilePart(targetFile.getName(), targetFile) 
                    };
            postMethod.setRequestEntity(new MultipartRequestEntity(parts, postMethod.getParams()));
            HttpClient client = new HttpClient();

            client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);

            status = client.executeMethod(postMethod);
            postMethod.releaseConnection();
        }
        catch (HttpException e) {
            throw e;
        }
        catch (IOException e) {
            throw e;
        }
        finally {
            if (postMethod != null) {
                postMethod.releaseConnection();
            }
        }
        return status;
    }

    /**
     * HttpClient下载文件
     * 
     * @param downloadUrl
     *            前台下载后台文件请求的url
     * @param fileName
     *            文件名称
     * @param filePath
     *            文件保存在前台的绝对路径（包括文件名）
     * @param localFilePath
     *            文件下载到前台的路径（文件的保存路径）
     * @param parameter
     *            用HashMap给PostMethod传参数
     * @return statusCode 远程http服务端返回的状态
     * @throws IOException
     */
    public static int httpClientDownload(String downloadUrl, String fileName, String localFilePath, String filePath,
            HashMap<String, String> parameter) throws IOException {
        HttpClient httpClient = new HttpClient();
        PostMethod postMethod = new PostMethod(downloadUrl);

        if (parameter != null && parameter.size() > 0) {
            Set<String> keySet = parameter.keySet();
            for (String string : keySet) {
                postMethod.setParameter(string, parameter.get(string));
            }
        }

        int statusCode = 0;
        OutputStream outputStream = null;
        try {
            statusCode = httpClient.executeMethod(postMethod);
            if (statusCode == HttpStatus.SC_OK) {
                File path = new File(localFilePath);
                if (!path.exists()) {
                    path.mkdir();
                }
                // 读取内容
                byte[] responseBody = postMethod.getResponseBody();
                outputStream = new FileOutputStream(new File(filePath));
                outputStream.write(responseBody);
                outputStream.flush();
                outputStream.close();
            }

        }
        catch (HttpException e) {
            throw e;
        }
        catch (IOException e) {
            throw e;
        }
        finally {
            if (outputStream != null) {
                outputStream.close();
            }
        }
        return statusCode;
    }

    /**
     * 接收上传文件，并保存到本地
     * 
     * @param request
     *            页面request请求
     * @param sizeThreshold
     *            内存中缓冲区大小
     * @param sizeMax
     *            最大文件限制
     * @param localFilePath
     *            本地文件路径
     * @param localFileName
     *            本地保存的文件名
     */
    @SuppressWarnings("unchecked")
    public static void upload(HttpServletRequest request, int sizeThreshold, int sizeMax, String localFilePath,
            String localFileName) {

        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(sizeThreshold);
        ServletFileUpload upload = new ServletFileUpload(factory);
        upload.setSizeMax(sizeMax);
        List<FileItem> items;
        try {
            items = upload.parseRequest(request);
        }
        catch (FileUploadException e) {
            e.printStackTrace();
            throw new RuntimeException("处理上传文件发生异常");
        }
        Iterator<FileItem> itr = items.iterator();
        while (itr.hasNext()) {
            FileItem item = (FileItem) itr.next();
            String fileName = item.getName();
            if (fileName != null) {
                // 前台保存路径不存在，创建
                File path = new File(localFilePath);
                if (!path.exists()) {
                    path.mkdir();
                }
                File file = new File(localFilePath, localFileName);
                try {
                    item.write(file);
                }
                catch (Exception e) {
                    throw new RuntimeException("从上传文件流中，输出内容到文件时发生异常");
                }
            }
        }
    }

    /**
     * 从本地下载文件。将文件放入response，返回给客户端浏览器
     * 
     * @param response
     *            页面响应
     * @param filePath
     *            文件保存在前台的绝对路径（包括文件名）
     * @param fileName
     *            文件名称
     * @throws IOException
     *             IO异常
     */
    public static void download(HttpServletResponse response, String filePath, String fileName) throws IOException {
        InputStream inStream = null;
        try {
            inStream = new FileInputStream(filePath);
            // 设置输出的格式
            response.reset();
            response.setContentType("application/x-msdownload");
            response.setCharacterEncoding("UTF-8");
            String filename = new String(fileName.getBytes("GBK"), "ISO8859_1");
            response.addHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
            // 循环取出流中的数据
            byte[] b = new byte[1024];
            int len;
            while ((len = inStream.read(b)) > 0)
                response.getOutputStream().write(b, 0, len);
            inStream.close();
        }
        catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("处理下载文件时发生IO异常");
        }
        finally {
            if (inStream != null) {
                inStream.close();
            }
        }
    }
    
    /**
     * 拷贝输入流到一个文件中
     * 方法功能描述
     * @Title: copyInputStreamToFile 
     * @Description: TODO
     * @param source
     * @param destination
     * @throws IOException
     */
	public static void copyInputStreamToFile(InputStream source,
			File destination) throws IOException {
		try {
			FileOutputStream output = openOutputStream(destination);
			try {
				IOUtils.copy(source, output);
				output.close();
			} finally {
				IOUtils.closeQuietly(output);
			}
		} finally {
			IOUtils.closeQuietly(source);
		}
	}

}
